package com.tuo51.evaluate.controller;


import com.github.binarywang.wxpay.bean.request.WxPayOrderQueryRequest;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.util.SignUtils;
import com.tuo51.evaluate.domain.appusers.PayWxOrder;
import com.tuo51.evaluate.service.appuser.PaymentService;
import com.tuo51.evaluate.service.appuser.ProductService;
import com.tuo51.foudation.constant.APPConstants;
import com.tuo51.foudation.model.APPErrorCode;
import com.tuo51.foudation.model.MemVerificationCache;
import com.tuo51.foudation.model.StatusResponse;
import com.tuo51.foudation.utils.PaymentUtils;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;

import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.POST;

@RestController
@RequestMapping("/eapi/pay")
@Slf4j
@Api(value = "/eapi/pay", tags = "测评 - 支付")
public class PayController {


    @Autowired
    ProductService productService;

    @Autowired
    WxPayService wxPayService;

    @Autowired
    WxPayConfig wxPayConfig;

    @Autowired
    PaymentService paymentService;

    @Autowired
    MemVerificationCache cache;


    @RequestMapping(value = "/order_list", method = GET, produces = "application/json")
    public StatusResponse orderList(@RequestHeader("ticket") String ticket ) {

        String userId = cache.getStaffId(ticket);

        List payOrder = paymentService.getAllOrdersForUser(userId);

        return StatusResponse.success(payOrder);
    }

    @RequestMapping(value = "/wx/order", method = GET, produces = "application/json")
    public StatusResponse wxOrder(@RequestHeader("ticket") String ticket,
                                  @RequestParam("productId") long productId,
                                  @RequestParam(value = "promoCode", required = false) String promoCode) {

        String userId = cache.getStaffId(ticket);

        Map<String,Object> result = null;

        try {
            result = paymentService.createWxVIPOrder(userId, productId, promoCode);
        } catch (WxPayException e) {
            log.error("微信支付异常:", e);
            return StatusResponse.error(APPErrorCode.CREATE_PAY_ORDER_FAIL.getCode(),e.getReturnMsg());
        } catch (JSONException e) {
            log.error("预料之外的异常:", e);
            return StatusResponse.error(APPErrorCode.CREATE_PAY_ORDER_FAIL.getCode(),e.getLocalizedMessage());
        }
        return StatusResponse.success(result);
    }

    @RequestMapping(value = "/wx/order/notify", method = POST, consumes={MediaType.APPLICATION_XML_VALUE,MediaType.TEXT_XML_VALUE}, produces={MediaType.APPLICATION_XML_VALUE,MediaType.TEXT_XML_VALUE})
    @ResponseBody
    public String wxOrderNotify(HttpServletRequest request,
                              HttpServletResponse response,
                                @RequestBody String requestXML) {


        Map<String, String> notifyMap = null;
        try {

            notifyMap = PaymentUtils.xml2Map(requestXML);
            log.info("微信支付回调:" + notifyMap);

            if (!SignUtils.checkSign(notifyMap, wxPayConfig.getSignType(), wxPayConfig.getMchKey())) {
                String ret = buildWxNotifyResult("FAIL", "check sign is failed");
                log.debug("return to wx server \n {}", ret);
                return ret;
            }

            return processWXOrderResult(notifyMap);
        } catch (Exception e) {
            log.error("微信支付通知异常 requestMap:" + notifyMap, e);
            String ret = buildWxNotifyResult("FAIL", "Internal Server Error");
            log.debug("return to wx server \n {}", ret);
            return ret;
        }
    }

    private String processWXOrderResult(Map<String, String> notifyMap){

        String resultCode = notifyMap.get("result_code");
        String transactionId = notifyMap.get("transaction_id");
        String outTradeNo = notifyMap.get("out_trade_no");
        String mchId = notifyMap.get("mch_id");
        String bankType = notifyMap.get("bank_type");
        String timeEnd = notifyMap.get("time_end");

        PayWxOrder payWxOrder = paymentService.getOrderByOrderNo(outTradeNo, APPConstants.PayType.WXPAY);
        if(payWxOrder.getProductIssueStatus().intValue() == APPConstants.ProductIssueStatus.ISSUE_SUCCESS.getValue()){
            return buildWxNotifyResult("SUCCESS", "OK");
        }

        payWxOrder.setTransactionId(transactionId);
        payWxOrder.setMchId(mchId);
        payWxOrder.setBankType(bankType);
        payWxOrder.setTimeEnd(timeEnd);
        payWxOrder.setResultCode(resultCode);

        if (!resultCode.equals("SUCCESS")) {
            payWxOrder.setStatus(APPConstants.PayOrderStatus.PAY_FAILED.getValue());
            paymentService.updateOrder(payWxOrder, APPConstants.PayType.WXPAY);
            return buildWxNotifyResult("FAIL", "result code is failed");
        }

        payWxOrder.setStatus(APPConstants.PayOrderStatus.PAY_SUCCESS.getValue());
        boolean finished = paymentService.finishWxOrder(payWxOrder, APPConstants.PayType.WXPAY);
        log.debug("微信支付回调:订单完成finished=" + finished);

        return buildWxNotifyResult("SUCCESS", "OK");
    }

    /**
     * /api/pay/wx/order/check
     * 订单检查接口
     * @param outTradeNo
     * @return
     */
    @RequestMapping(value = "/wx/order/check", method = GET, produces = "application/json")
    public StatusResponse wxOrderCheck(@RequestHeader("ticket") String ticket,
                                       @RequestParam("outTradeNo") String outTradeNo) {


        WxPayOrderQueryRequest wxPayOrderQueryRequest = WxPayOrderQueryRequest.newBuilder()
                .outTradeNo(outTradeNo)
                .build();

        try {
            WxPayOrderQueryResult wxPayOrderQueryResult = wxPayService.queryOrder(wxPayOrderQueryRequest);
            String tradeState = wxPayOrderQueryResult.getTradeState();
            if (tradeState.equals("SUCCESS")) {

                PayWxOrder payWxOrder = paymentService.getOrderByOrderNo(outTradeNo, APPConstants.PayType.WXPAY);

                if(payWxOrder == null){
                    return StatusResponse.error(APPErrorCode.ORDER_PAY_FAIL.getCode(), "无效订单号");
                }

                payWxOrder.setTransactionId(wxPayOrderQueryResult.getTransactionId());
                payWxOrder.setMchId(wxPayOrderQueryResult.getMchId());
                payWxOrder.setBankType(wxPayOrderQueryResult.getBankType());
                payWxOrder.setTimeEnd(wxPayOrderQueryResult.getTimeEnd());
                payWxOrder.setResultCode(wxPayOrderQueryResult.getResultCode());

                payWxOrder.setStatus(APPConstants.PayOrderStatus.PAY_SUCCESS.getValue());
                boolean finished = paymentService.finishWxOrder(payWxOrder, APPConstants.PayType.WXPAY);

                return StatusResponse.success(finished);
            } else {
                return StatusResponse.error(APPErrorCode.ORDER_PAY_FAIL.getCode(), APPErrorCode.ORDER_PAY_FAIL.getDescription());
            }

        } catch (WxPayException e) {
            log.error(e.getMessage(), e);
            return StatusResponse.error(APPErrorCode.PAY_WX_ERROR.getCode(), APPErrorCode.PAY_WX_ERROR.getDescription());
         } catch (Exception e) {
            log.error(e.getMessage(), e);
            return StatusResponse.error(APPErrorCode.UNSPECIFIED.getCode(), e.getMessage());
        }

    }

    private String buildWxNotifyResult(String resultCode, String resultMessage) {
        return "<xml><return_code><![CDATA[" + resultCode + "]]></return_code><return_msg><![CDATA[" + resultMessage + "]]></return_msg></xml>";
    }

}
